using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SilkSharp
{
	/*
	 *The Decoder API.
	 *
	 * @author Jing Dai
	 * @author Dingxin Xu
	 */
	public class Silk_dec_API
	{
		/*
		 * The <tt>Logger</tt> used by the <tt>Silk_dec_API</tt> class and its
		 * instances for logging output.
		 */
		//private static final Logger logger = Logger.getLogger(Silk_dec_API.class);

		/*
		 * Get the memory size for the decoder state struct. 
		 * It's not required in Java.
		 * 
		 * @deprecated
		 * @param decSizeBytes the decoder state size in bytes
		 * @return
		 */
		static int SKP_Silk_SDK_Get_Decoder_Size( int[] decSizeBytes )
		{
			int ret = 0;
			return ret;
		}

		/*
		 * Reset the decoder state.
		 * 
		 * @param decState the decoder state
		 * @return ret 
		 */
		static int SKP_Silk_SDK_InitDecoder(
				Object decState                                      /* I/O: State                                          */
		)
		{
			int ret = 0;
			SKP_Silk_decoder_state struc;
			struc = (SKP_Silk_decoder_state)decState;
			ret = Silk_create_init_destroy.SKP_Silk_init_decoder( struc );

			return ret;
		}

		/*
		 * Decode a frame.
		 * 
		 * @param decState the decoder state.
		 * @param decControl the decoder control.
		 * @param lostFlag the lost flag. 0: no loss; 1: loss.
		 * @param inData encoding input vector.
		 * @param inData_offset the actual data offset in the input vector.
		 * @param nBytesIn number of input bytes.
		 * @param samplesOut decoded output speech vector.
		 * @param samplesOut_offset the actual data offset in the output vector.
		 * @param nSamplesOut number of samples.
		 * @return the returned value carries the error message. 
		 * 0 indicates OK; other indicates error.
		 */
		static int SKP_Silk_SDK_Decode(
				Object decState,       /* I/O: State                                           */
				SKP_SILK_SDK_DecControlStruct decControl,     /* I/O: Control structure                               */
				int lostFlag,       /* I:   0: no loss, 1 loss                              */
				byte[] inData,        /* I:   Encoded input vector                            */
				int inData_offset,
				int nBytesIn,       /* I:   Number of input Bytes                           */
				short[] samplesOut,    /* O:   Decoded output speech vector                    */
				int samplesOut_offset,
				short[] nSamplesOut    /* I/O: Number of samples (vector/decoded)              */
		)
		{
			int ret = 0, used_bytes, prev_fs_kHz;
			SKP_Silk_decoder_state psDec;

			psDec = (SKP_Silk_decoder_state)decState;

			/**********************************/
			/* Test if first frame in payload */
			/**********************************/
			if( psDec.moreInternalDecoderFrames == 0 )
			{
				/* First Frame in Payload */
				psDec.nFramesDecoded = 0;  /* Used to count frames in packet */
			}

			if( psDec.moreInternalDecoderFrames == 0 &&    /* First frame in packet    */
				lostFlag == 0 &&                            /* Not packet loss          */
				nBytesIn > Silk_define.MAX_ARITHM_BYTES )
			{             /* Too long payload         */
				/* Avoid trying to decode a too large packet */
				lostFlag = 1;
				ret = Silk_errors.SKP_SILK_DEC_PAYLOAD_TOO_LARGE;
			}

			/* Save previous sample frequency */
			prev_fs_kHz = psDec.fs_kHz;

			/* Call decoder for one frame */
			int[] used_bytes_ptr = new int[ 1 ];
			ret += Silk_decode_frame.SKP_Silk_decode_frame( psDec, samplesOut, samplesOut_offset, nSamplesOut, inData, inData_offset,
					nBytesIn, lostFlag, used_bytes_ptr );
			used_bytes = used_bytes_ptr[ 0 ];

			if( used_bytes != 0 ) /* Only Call if not a packet loss */
			{
				if( psDec.nBytesLeft > 0 && psDec.FrameTermination == Silk_define.SKP_SILK_MORE_FRAMES && psDec.nFramesDecoded < 5 )
				{
					/* We have more frames in the Payload */
					psDec.moreInternalDecoderFrames = 1;
				}
				else
				{
					/* Last frame in Payload */
					psDec.moreInternalDecoderFrames = 0;
					psDec.nFramesInPacket = psDec.nFramesDecoded;

					/* Track inband FEC usage */
					if( psDec.vadFlag == Silk_define.VOICE_ACTIVITY )
					{
						if( psDec.FrameTermination == Silk_define.SKP_SILK_LAST_FRAME )
						{
							psDec.no_FEC_counter++;
							if( psDec.no_FEC_counter > Silk_define.NO_LBRR_THRES )
							{
								psDec.inband_FEC_offset = 0;
							}
						}
						else if( psDec.FrameTermination == Silk_define.SKP_SILK_LBRR_VER1 )
						{
							psDec.inband_FEC_offset = 1; /* FEC info with 1 packet delay */
							psDec.no_FEC_counter = 0;
						}
						else if( psDec.FrameTermination == Silk_define.SKP_SILK_LBRR_VER2 )
						{
							psDec.inband_FEC_offset = 2; /* FEC info with 2 packets delay */
							psDec.no_FEC_counter = 0;
						}
					}
				}
			}

			if( Silk_define.MAX_API_FS_KHZ * 1000 < decControl.API_sampleRate ||
				8000 > decControl.API_sampleRate )
			{
				ret = Silk_errors.SKP_SILK_DEC_INVALID_SAMPLING_FREQUENCY;
				return ( ret );
			}

			/* Resample if needed */
			if( psDec.fs_kHz * 1000 != decControl.API_sampleRate )
			{
				short[] samplesOut_tmp = new short[ Silk_define.MAX_API_FS_KHZ * Silk_define.FRAME_LENGTH_MS ];
				Silk_typedef.SKP_assert( psDec.fs_kHz <= Silk_define.MAX_API_FS_KHZ );

				/* Copy to a tmp buffer as the resampling writes to samplesOut */
				System.Array.Copy( samplesOut, samplesOut_offset + 0, samplesOut_tmp, 0, nSamplesOut[ 0 ] );
				/* (Re-)initialize resampler state when switching internal sampling frequency */
				if( prev_fs_kHz != psDec.fs_kHz || psDec.prev_API_sampleRate != decControl.API_sampleRate )
				{
					ret = Silk_resampler.SKP_Silk_resampler_init( psDec.resampler_state, psDec.fs_kHz * 1000, decControl.API_sampleRate );
				}

				/* Resample the output to API_sampleRate */
				ret += Silk_resampler.SKP_Silk_resampler( psDec.resampler_state, samplesOut, samplesOut_offset, samplesOut_tmp, 0, nSamplesOut[ 0 ] );

				/* Update the number of output samples */
				nSamplesOut[ 0 ] = (short)( (int)( nSamplesOut[ 0 ] * decControl.API_sampleRate ) / ( psDec.fs_kHz * 1000 ) );
			}

			psDec.prev_API_sampleRate = decControl.API_sampleRate;

			/* Copy all parameters that are needed out of internal structure to the control stucture */
			decControl.frameSize = (int)psDec.frame_length;
			decControl.framesPerPacket = (int)psDec.nFramesInPacket;
			decControl.inBandFECOffset = (int)psDec.inband_FEC_offset;
			decControl.moreInternalDecoderFrames = (int)psDec.moreInternalDecoderFrames;

			return ret;
		}

		/*
		 * Find LBRR information in a packet.
		 * 
		 * @param inData encoded input vector.
		 * @param inData_offset offset of the valid data.
		 * @param nBytesIn number of input bytes.
		 * @param lost_offset offset from lost packet.
		 * @param LBRRData LBRR payload.
		 * @param LBRRData_offset offset of the valid data.
		 * @param nLBRRBytes number of LBRR bytes.
		 */
		static void SKP_Silk_SDK_search_for_LBRR(
				byte[] inData,        /* I:   Encoded input vector                            */
				int inData_offset,
				short nBytesIn,       /* I:   Number of input Bytes                           */
				int lost_offset,    /* I:   Offset from lost packet                         */
				byte[] LBRRData,      /* O:   LBRR payload                                    */
				int LBRRData_offset,
				short[] nLBRRBytes     /* O:   Number of LBRR Bytes                            */
		)
		{
			SKP_Silk_decoder_state sDec = new SKP_Silk_decoder_state(); // Local decoder state to avoid interfering with running decoder */
			SKP_Silk_decoder_control sDecCtrl = new SKP_Silk_decoder_control();
			int[] TempQ = new int[ Silk_define.MAX_FRAME_LENGTH ];

			if( lost_offset < 1 || lost_offset > Silk_define.MAX_LBRR_DELAY )
			{
				/* No useful FEC in this packet */
				nLBRRBytes[ 0 ] = 0;
				return;
			}

			sDec.nFramesDecoded = 0;
			sDec.fs_kHz = 0; /* Force update parameters LPC_order etc */
			Silk_macros.FillArray( sDec.prevNLSF_Q15, 0, Silk_define.MAX_LPC_ORDER, 0 );

			for( int i = 0; i < Silk_define.MAX_LPC_ORDER; i++ )
				sDec.prevNLSF_Q15[ i ] = 0;

			Silk_range_coder.SKP_Silk_range_dec_init( sDec.sRC, inData, inData_offset, (int)nBytesIn );

			while( true )
			{
				Silk_decode_parameters.SKP_Silk_decode_parameters( sDec, sDecCtrl, TempQ, 0 );
				if( sDec.sRC.error != 0 )
				{
					/* Corrupt stream */
					nLBRRBytes[ 0 ] = 0;
					return;
				}
				//TODO:note the semicolon;
				//          };
				if( ( ( sDec.FrameTermination - 1 ) & lost_offset ) != 0 && sDec.FrameTermination > 0 && sDec.nBytesLeft >= 0 )
				{
					/* The wanted FEC is present in the packet */
					nLBRRBytes[ 0 ] = (short)sDec.nBytesLeft;
					System.Array.Copy( inData, inData_offset + nBytesIn - sDec.nBytesLeft, LBRRData, LBRRData_offset + 0, sDec.nBytesLeft );
					break;
				}
				if( sDec.nBytesLeft > 0 && sDec.FrameTermination == Silk_define.SKP_SILK_MORE_FRAMES )
				{
					sDec.nFramesDecoded++;
				}
				else
				{
					LBRRData = null;
					nLBRRBytes[ 0 ] = 0;
					break;
				}
			}
		}

		/*
		 * Getting type of content for a packet.
		 * @param inData encoded input vector.
		 * @param nBytesIn number of input bytes.
		 * @param Silk_TOC type of content.
		 */
		static void SKP_Silk_SDK_get_TOC(
				 byte[] inData,        /* I:   Encoded input vector                            */
				 short nBytesIn,       /* I:   Number of input bytes                           */
				SKP_Silk_TOC_struct Silk_TOC       /* O:   Type of content                                 */
			)
		{
			SKP_Silk_decoder_state sDec = new SKP_Silk_decoder_state();
			SKP_Silk_decoder_control sDecCtrl = new SKP_Silk_decoder_control();
			int[] TempQ = new int[ Silk_define.MAX_FRAME_LENGTH ];

			sDec.nFramesDecoded = 0;
			sDec.fs_kHz = 0; /* Force update parameters LPC_order etc */
			Silk_range_coder.SKP_Silk_range_dec_init( sDec.sRC, inData, 0, (int)nBytesIn );

			Silk_TOC.corrupt = 0;
			while( true )
			{
				Silk_decode_parameters.SKP_Silk_decode_parameters( sDec, sDecCtrl, TempQ, 0 );

				Silk_TOC.vadFlags[ sDec.nFramesDecoded ] = sDec.vadFlag;
				Silk_TOC.sigtypeFlags[ sDec.nFramesDecoded ] = sDecCtrl.sigtype;

				if( sDec.sRC.error != 0 )
				{
					/* Corrupt stream */
					Silk_TOC.corrupt = 1;
					break;
				}
				//TODO:note the semicolon;
				//          };
				if( sDec.nBytesLeft > 0 && sDec.FrameTermination == Silk_define.SKP_SILK_MORE_FRAMES )
				{
					sDec.nFramesDecoded++;
				}
				else
				{
					break;
				}
			}
			if( Silk_TOC.corrupt != 0 || sDec.FrameTermination == Silk_define.SKP_SILK_MORE_FRAMES ||
				sDec.nFramesInPacket > Silk_SDK_API.SILK_MAX_FRAMES_PER_PACKET )
			{
				/* Corrupt packet */
				{
					Silk_TOC.corrupt = 0;
					Silk_TOC.framesInPacket = 0;
					Silk_TOC.fs_kHz = 0;
					Silk_TOC.inbandLBRR = 0;

					for( int i = 0; i < Silk_TOC.vadFlags.length; i++ )
						Silk_TOC.vadFlags[ i ] = 0;
					for( int i = 0; i < Silk_TOC.sigtypeFlags.length; i++ )
						Silk_TOC.sigtypeFlags[ i ] = 0;
				}
				Silk_TOC.corrupt = 1;
			}
			else
			{
				Silk_TOC.framesInPacket = sDec.nFramesDecoded + 1;
				Silk_TOC.fs_kHz = sDec.fs_kHz;
				if( sDec.FrameTermination == Silk_define.SKP_SILK_LAST_FRAME )
				{
					Silk_TOC.inbandLBRR = sDec.FrameTermination;
				}
				else
				{
					Silk_TOC.inbandLBRR = sDec.FrameTermination - 1;
				}
			}
		}

		/*
		 * Get the version number.
		 * @return the string specifying the version number.
		 */
		static String SKP_Silk_SDK_get_version()
		{
			String version = "1.0.6";
			return version;
		}
	}
}
